#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "v_stack.h"

/*=======================
 * Getter functions
 *======================*/

uint32_t v_stack_size(v_stack_ptr_t stack)
{
    return stack->size;
}

bool v_stack_empty(v_stack_ptr_t stack)
{
    return (stack->size == 0);
}

v_data_ptr_t v_stack_top(v_stack_ptr_t stack)
{
    return !v_stack_empty(stack) ? stack->top->data_ptr : stack->null_data_ptr;
}

/*=====================
 * Setter functions
 *====================*/

vlib_status_t v_stack_push(v_stack_ptr_t stack, v_data_ptr_t data_ptr, uint32_t data_size, copy_data_f copy_data)
{
    v_stack_node_t* node = (v_stack_node_t* )v_malloc(sizeof (v_stack_node_t));
    if(node == NULL) {
        return VLIB_ERROR;
    }
    node->data_ptr = (v_data_ptr_t) v_malloc(data_size);
    if(node->data_ptr == NULL) {
        return VLIB_ERROR;
    }

    if (copy_data != NULL) {
        copy_data(node->data_ptr, data_ptr);
    } else {
        memcpy(node->data_ptr, data_ptr, data_size);
    }

    node->next = stack->top;
    stack->top = node;
    ++stack->size;

    return VLIB_OK;
}

vlib_status_t v_stack_pop(v_stack_ptr_t stack)
{
    if(stack->top == NULL) {
        return VLIB_ERROR;
    }
    v_stack_node_t* p = stack->top;
    stack->top = stack->top->next;
    v_free(p->data_ptr);
    v_free(p);
    --stack->size;

    return VLIB_OK;
}

void v_stack_clear(v_stack_ptr_t stack)
{
    while (!v_stack_empty(stack)) {
        v_stack_pop(stack);
    }
}

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

v_stack_ptr_t v_stack_create(uint32_t type_size)
{
    v_stack_ptr_t stack = (v_stack_ptr_t)v_malloc(sizeof(v_stack_t));
    if(stack == NULL) {
        return NULL;
    }
    stack->null_data_ptr = (v_data_ptr_t)v_malloc(type_size);    //确保在容器为空时正常访问
    if(stack->null_data_ptr == NULL) {
        return NULL;
    }
    memset(stack->null_data_ptr, '\0', type_size);

    stack->top = NULL;
    stack->size = 0;

    return stack;
}

void v_stack_destroy(v_stack_ptr_t stack)
{
    v_stack_clear(stack);
    v_free(stack->null_data_ptr);
    v_free(stack);
}
